﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.IO;
using System.Reflection;
using FRW.Common.Configuration;
using FRW.Common.Extensions;
using FRW.Common.FileSystem;
using FRW.Common;

namespace FileRenamer.GUI
{
    // TODO fix issue that if name has not changed the file is not moved to a new destination folder
    // TODO load save needs sorted as this does not always work as expected
    // TODO add an option to default configuration to either video or books or include files as part of install
    // TODO change file name and associated with application
    // TODO ensure that the threads are closed properly before exit is carried out
    // TODO consider re-implementing the tool tip as a form and avoid it taking focus etc. should always be on top (bookmarked info on this)
    public partial class Main : Form
    {
        private string _configurationFile = null;
        private MessageType _outputLevel = MessageType.INFORMATION;
        private TheDoc _doc;
        private Logger _logger;
        private Timer _actionTimer = new Timer();

        private bool LockGrid = false;

        private RtfToolTip _toolTip;

        private Int64 _lastActionSerialNumber = -1;

        public Main(TheDoc doc)
        {
            InitializeComponent();

            // add our tooltip popup and make sure it is front most control (index 0)
            _toolTip = new RtfToolTip(this);
            this.Controls.Add(_toolTip);
            this.Controls.SetChildIndex(_toolTip, 0);

            AddToolTips();

            // clear all of the status text as we have nothing to display yet
            StatusText();

            // initialise timer for updating the action list data grid
            _actionTimer.Interval = 100;
            _actionTimer.Tick += new EventHandler(m_actionTimer_Tick);

            // do not add any columns when the data source is changed, they are all added in the designer
            _actionsGrid.AutoGenerateColumns = false;
            _expressionGrid.AutoGenerateColumns = false;

            _doc = doc;
            _logger = _doc.Logger;

            _statusOutputLevel.Items.AddRange(Enum.GetNames(typeof(MessageType)));
            _statusOutputLevel.Text = _outputLevel.ToString();

            if (string.IsNullOrWhiteSpace(Properties.Settings.Default.LastConfigFile))
            {
                _configurationFile = Properties.Settings.Default.LastConfigFile = PathManager.Instance.GetApplicationFile("Configuration.xml");
            }
            else
            {
                _configurationFile = Properties.Settings.Default.LastConfigFile;
            }


            LoadConfiguration(_configurationFile);
            ApplyConfiguration();

            if (Properties.Settings.Default.Height > 0 && Properties.Settings.Default.Width > 0)
            {
                Height = Properties.Settings.Default.Height;
                Width = Properties.Settings.Default.Width;
            }

            ConfigureDataGrid();

            UpdateTitle(_configurationFile);

            _actionTimer.Start();
        }

        private void AddToolTips()
        {
            _MainToolTip.SetToolTip(_movefiles, "Determines whether files should be moved or copied");
            _MainToolTip.SetToolTip(_recursiveScan, "Scan source folder recursively looking for files matching the extension list");
            _MainToolTip.SetToolTip(_overwrite, "Overwrite destination files if they already exist, otherwise an error will be flagged");
            _MainToolTip.SetToolTip(_matchDestination, "Try and match the destination file name to a suitable folder under the destination folder (e.g. BBC - Horizon would match the folder [destination]\\BBC\\Horizon)");
            _MainToolTip.SetToolTip(_stripFolderName, "Strip the matching portion of a file name if a match was found with smart matching");
            _MainToolTip.SetToolTip(_debug, "Do not perform action, only show what the results would be");

            _MainToolTip.SetToolTip(_source, "Source folder to search for files");
            _MainToolTip.SetToolTip(_destination, "Base folder that should be used for the destination of updated files");
        }

        void m_actionTimer_Tick(object sender, EventArgs e)
        {
            if (_doc.ActionFinished == false)
            {
                try
                {
                    _cancelButton.Text = "Cancel";
                    _cancelButton.Enabled = true;
                    _actionButton.Enabled = false;
                    _parseButton.Enabled = false;
                    _scanButton.Enabled = false;
                }
                catch
                {
                }
            }
            else
            {
                if (_doc.ActionCancel == true)
                {
                    _cancelButton.Text = "Stopped!";
                }
                else
                {
                    _cancelButton.Text = "Finished!";
                }
                _cancelButton.Enabled = false;
                _actionButton.Enabled = true;
                _parseButton.Enabled = true;
                _scanButton.Enabled = true;
            }

            if (!LockGrid)
            {
                LockGrid = true;
                if ((_actionsGrid.Rows.Count != _doc.Actions.Count) || (_lastActionSerialNumber < ActionItem.SerialNumber))
                {
                    if ((_doc.Actions != _actionsGrid.DataSource))
                    {
                        //_actionsGrid.DataSource = null;
                        _doc.Actions.SetSynchronise(_actionsGrid);
                        _actionsGrid.DataSource = _doc.Actions;
                    }
                    _actionsGrid.Refresh();
                    _lastActionSerialNumber = ActionItem.SerialNumber;
                }
                LockGrid = false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void ConfigureDataGrid()
        {
            // double buffer to remove flicker from data grid when updated
            _actionsGrid.DoubleBuffered(true);
            _expressionGrid.DoubleBuffered(true);

            clmType.DataSource = Enum.GetValues(typeof(RegReplace.RegExpType));
            clmAction.DataSource = Enum.GetValues(typeof(ActionItem.ActionType));

            _expressionGrid.DataSource = _doc.Configuration.ExpressionList;
        }

        private void btnSelectSource_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();

            folderDialog.Description = "Select Source Folder";
            folderDialog.ShowNewFolderButton = false;
            folderDialog.SelectedPath = _source.Text;
            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                _source.Text = _doc.Configuration.SourceDir = folderDialog.SelectedPath;
            }
        }

        private void UpdateProgress(int percentage)
        {
            if(_progressBar.InvokeRequired)
            {
                MethodInvoker del = delegate { UpdateProgress(percentage); };
                _progressBar.Invoke(del);
            }
            else
            {
                _progressBar.Value = percentage;
            }

        }

        private void btnSelectDestination_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();

            folderDialog.Description = "Select Destination Folder";
            folderDialog.ShowNewFolderButton = true;
            folderDialog.SelectedPath = _destination.Text;
            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                _destination.Text = _doc.Configuration.DestinationDir = folderDialog.SelectedPath;
            }
        }

        private void btnAddExtension_Click(object sender, EventArgs e)
        {
            if (_extension.Text != "")
            {
                _doc.Configuration.Extensions.Add(_extension.Text);
            }
            _extension.Text = "";
        }

        private void lbExtensions_DoubleClick(object sender, EventArgs e)
        {
            if ((_extensionList.SelectedIndex != -1) && (_extensionList.SelectedItem.ToString() != null))
            {
                _extension.Text = _extensionList.SelectedItem.ToString();
                _doc.Configuration.Extensions.Remove(_extension.Text);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.Height = Height;
            Properties.Settings.Default.Width = Width;

            // TODO we should consider saving the column widths for the data grids

            Properties.Settings.Default.LastConfigFile = _configurationFile;
            Properties.Settings.Default.Save();

            _doc.Save(_configurationFile);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnScan_Click(object sender, EventArgs e)
        {
            _doc.ClearFilters();
            UpdateDataDisplays();

            string sourceFolder = _source.Text;

            try
            {
                _doc.ActionScanFiles(UpdateProgress);
                _doc.CompleteHandler = ScanComplete;
            }
            catch (DirectoryNotFoundException)
            {
                MessageBox.Show("Error - Source folder does not exist!", "Source Folder Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnParse_Click(object sender, EventArgs e)
        {
            // TODO we need to call this to reorder list, it will be changed in the future. Check for other places where this is called
            UpdateDataDisplays();

            _doc.ActionParseFiles(UpdateProgress);
            _doc.CompleteHandler = ParseComplete;
        }

        private void btnAction_Click(object sender, EventArgs e)
        {
            _doc.ActionMoveFiles(UpdateProgress);
            _doc.CompleteHandler = ActionComplete;
        }

        private void ScanComplete()
        {
            if (_actionsGrid.InvokeRequired)
            {
                MethodInvoker del = delegate { ScanComplete(); };
                _actionsGrid.Invoke(del);
            }
            else
            {
                StatusText("Scanned", _doc.Actions.GetItemCount(ActionItem.ActionType.SCANNED).ToString());
            }
        }

        private void ParseComplete()
        {
            if (_actionsGrid.InvokeRequired)
            {
                MethodInvoker del = delegate { ParseComplete(); };
                _actionsGrid.Invoke(del);
            }
            else
            {
                string root = Directory.GetDirectoryRoot(_doc.Configuration.DestinationDir);
                DriveInfo driveInfo = new DriveInfo(root);
                long freeSpace = driveInfo.TotalFreeSpace;

                StatusText("Move", _doc.Actions.GetItemCount(ActionItem.ActionType.MOVE).ToString(),
                            "Ignore", _doc.Actions.GetItemCount(ActionItem.ActionType.IGNORE).ToString(),
                            "No Change", _doc.Actions.GetItemCount(ActionItem.ActionType.NOCHANGE).ToString(),
                            "Size", _doc.Actions.GetFileSetSize().ToDiskSize(),
                            "Destination Space", freeSpace.ToDiskSize());
            }
        }

        private void ActionComplete()
        {
            if (_actionsGrid.InvokeRequired)
            {
                MethodInvoker del = delegate { ActionComplete(); };
                _actionsGrid.Invoke(del);
            }
            else
            {
                StatusText("Moved", _doc.Actions.GetItemCount(ActionItem.ActionType.MOVED).ToString(),
                            "Ignored", _doc.Actions.GetItemCount(ActionItem.ActionType.IGNORE).ToString(),
                            "Error", _doc.Actions.GetItemCount(ActionItem.ActionType.ERROR).ToString());

            }
        }

        private void parseFileNames()
        {
        }

        private void tbDestination_TextChanged(object sender, EventArgs e)
        {
            _doc.Configuration.DestinationDir = _destination.Text;
        }

        private void tbSource_TextChanged(object sender, EventArgs e)
        {
            _doc.Configuration.SourceDir = _source.Text;
        }

        private void mnuSaveAs_Click(object sender, EventArgs e)
        {
            // TODO we need to account for file handling better when default configurations are not set.
            SaveFileDialog fileDialog = new SaveFileDialog();

            if (!String.IsNullOrWhiteSpace(_configurationFile))
            {
                FileInfo cfi = new FileInfo(_configurationFile);
                fileDialog.DefaultExt = cfi.Extension;
                fileDialog.FileName = cfi.Name;
            }
            else
            {
                fileDialog.DefaultExt = ".xml";
            }

            fileDialog.InitialDirectory = PathManager.Instance.ApplicationFolder;
            fileDialog.AddExtension = true;
            fileDialog.Filter = "XML (*.xml)|*.xml|Binary (*.bin)|*.bin|All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                FileInfo fi = new FileInfo(fileDialog.FileName);
                _configurationFile = fi.FullName;
                SaveConfiguration(_configurationFile);
            }
        }

        private void mnuReload_Click(object sender, EventArgs e)
        {
            LoadConfiguration(_configurationFile);
        }

        private void mnuLoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.InitialDirectory = PathManager.Instance.ApplicationFolder;
            fileDialog.Filter = "XML (*.xml)|*.xml|Binary (*.bin)|*.bin|All Files (*.*)|*.*";
            fileDialog.Multiselect = false;
            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                LoadConfiguration(fileDialog.FileName);
            }
        }

        private void mnuSave_Click(object sender, EventArgs e)
        {
            _doc.Configuration.Debug = _debug.Checked;
            _doc.Configuration.Move = _movefiles.Checked;
            _doc.Configuration.Recursive = _recursiveScan.Checked;

            if (_configurationFile != null)
            {
                SaveConfiguration(_configurationFile);
            }
        }

        private void LoadConfiguration(string fileName)
        {
            _doc.Load(fileName);
            ApplyConfiguration();
            _configurationFile = fileName;
            UpdateTitle(fileName);
        }

        private void SaveConfiguration(string fileName)
        {
            _doc.Save(fileName);
            UpdateTitle(fileName);
        }

        private void ApplyConfiguration()
        {
            _source.Text = _doc.Configuration.SourceDir;
            _destination.Text = _doc.Configuration.DestinationDir;
            _debug.Checked = _doc.Configuration.Debug;
            _movefiles.Checked = _doc.Configuration.Move;
            _recursiveScan.Checked = _doc.Configuration.Recursive;
            _overwrite.Checked = _doc.Configuration.Overwrite;
            _matchDestination.Checked = _doc.Configuration.MatchDestinationFolder;
            _extensionList.DataSource = _doc.Configuration.Extensions;
            _autoSort.Checked = _doc.Configuration.AutoSortExpressions;
            _statusOutputLevel.Text = _doc.Configuration.StatusLevel.ToString();
            _stripFolderName.Checked = _doc.Configuration.StripFolderName;

            UpdateDataDisplays();
        }

        private void UpdateDataDisplays()
        {
            if (_doc.Configuration.AutoSortExpressions)
            {
                _doc.OrderRulesByPriority();
            }

            _expressionGrid.DataSource = _doc.Configuration.ExpressionList;
            _actionsGrid.Refresh();
        }

        private void mnuExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void tsDestFolders_Click(object sender, EventArgs e)
        {
            // create a list of all destination folders that we could maybe use.
            DirectoryStructure directoryStructure = new DirectoryStructure(_doc.Configuration.DestinationDir);

            foreach (DestinationDirectoryMatch data in directoryStructure.DirectoryLocations(_doc.Configuration.DestinationDir))
            {
                _logger.Log("Directory - " + data.RegularExpression + " - " + data.Folder, MessageType.DEBUG, Color.Red, true);
            }

            OutputText output = new OutputText();

            output.RtfText = _logger.GetLoggerText();
            output.ShowDialog();
        }

        private void dgRegExpressions_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }

        private void dgRegExpressions_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
        }

        private void dgRegExpressions_UserAddedRow(object sender, DataGridViewRowEventArgs e)
        {

        }

        private void dgRegExpressions_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
        {
            switch (e.StateChanged)
            {
                case DataGridViewElementStates.Selected:
                    break;
            }
        }

        private void dgRegExpressions_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
        {
            // TODO this is disabled at present as it causes funny behaviour depending on current cell when the mouse moves
            //return;

            DataGridView grid = sender as DataGridView;

            if (grid != null)
            {
                if (e.ColumnIndex >= 0 && e.ColumnIndex < grid.Columns.Count)
                {
                    DataGridViewColumn column = grid.Columns[e.ColumnIndex];

                    switch (column.HeaderText)
                    {
                        case "Type":
                            grid.EditMode = DataGridViewEditMode.EditOnEnter;
                            break;
                        default:
                            grid.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2;
                            break;
                    }
                }
                else
                {
                    // TODO tidy this up so that the mode is only changed when in the row header
                }
            }
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_doc.Configuration != null)
            {
                _doc.Configuration.StatusLevel = (MessageType)Enum.Parse(typeof(MessageType), _statusOutputLevel.Text);
                _logger.SetLevel(_doc.Configuration.StatusLevel);
            }
        }

        private void cbMatchDestinationFolder_CheckedChanged(object sender, EventArgs e)
        {
            _doc.Configuration.MatchDestinationFolder = _matchDestination.Checked;
            _stripFolderName.Enabled = _matchDestination.Checked;
            if (_doc.Configuration.MatchDestinationFolder == false)
            {
                _stripFolderName.Checked = false;
            }
        }

        private void cbStripFolderName_CheckedChanged(object sender, EventArgs e)
        {
            _doc.Configuration.StripFolderName = _stripFolderName.Checked;
        }

        private void cbMoveFiles_CheckedChanged(object sender, EventArgs e)
        {
            if (_doc.Configuration.Move != _movefiles.Checked)
            {
                if (_actionsGrid.RowCount > 0)
                {
                    if (MessageBox.Show("This will clear the current file list, do you want to continue", "Clear List", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes)
                    {
                        // TODO we should do this via a method in the m_doc class
                        _doc.Actions.Clear();
                        _actionsGrid.DataSource = null;
                        _actionsGrid.Rows.Clear();

                        _destination.Enabled = _movefiles.Checked;
                        _doc.Configuration.Move = _movefiles.Checked;
                    }
                    else
                    {
                        _movefiles.Checked = _doc.Configuration.Move;
                    }
                }
                else
                {
                    _doc.Configuration.Move = _movefiles.Checked;
                }
            }
        }

        private void tbRecursiveScan_CheckedChanged(object sender, EventArgs e)
        {
            _doc.Configuration.Recursive = _recursiveScan.Checked;
        }

        private void dgRegExpressions_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            // Changes how cells are displayed depending on their columns and values.

        }

        private void dgActionList_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            DataGridView dataGrid = sender as DataGridView;

            if (dataGrid != null)
            {
                if (e.RowIndex > 0)
                {
                    ActionItem action = (ActionItem)dataGrid.Rows[e.RowIndex].DataBoundItem;

                    // colour code the rows for each action that we are going to take
                    switch (action.Action)
                    {
                        case ActionItem.ActionType.IGNORE:
                            e.CellStyle.BackColor = Color.LightCoral;
                            e.CellStyle.SelectionBackColor = Color.Coral;
                            break;

                        case ActionItem.ActionType.NOCHANGE:
                            e.CellStyle.BackColor = Color.LightSalmon;
                            e.CellStyle.SelectionBackColor = Color.DarkSalmon;
                            break;

                        case ActionItem.ActionType.DELETED:
                            e.CellStyle.BackColor = Color.Gray;
                            e.CellStyle.SelectionBackColor = Color.DarkGray;
                            break;

                        case ActionItem.ActionType.COPIED:
                        case ActionItem.ActionType.MOVED:
                            e.CellStyle.BackColor = Color.LightGreen;
                            e.CellStyle.SelectionBackColor = Color.DarkGreen;
                            break;

                        case ActionItem.ActionType.ERROR:
                            e.CellStyle.BackColor = Color.Red;
                            e.CellStyle.SelectionBackColor = Color.DarkRed;
                            break;
                    }

                    // display in bold if the destination already exists
                    if ((action.Action == ActionItem.ActionType.MOVE) && File.Exists(action.Destination))
                    {
                        e.CellStyle.ForeColor = Color.Red;
                        e.CellStyle.Font = new Font(e.CellStyle.Font.FontFamily, e.CellStyle.Font.Size, FontStyle.Bold);
                    }
                }
            }
        }

        private void dgActionList_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dataGrid = sender as DataGridView;

            if (dataGrid != null)
            {
                if (e.RowIndex >= 0 && e.RowIndex <= dataGrid.Rows.Count)
                {
                    try
                    {
                        ActionItem action = (ActionItem)dataGrid.Rows[e.RowIndex].DataBoundItem;
                        _toolTip.RtfText = action.LogText;
                    }
                    catch
                    {
                    }
                }
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            _doc.ActionCancel = true;
        }

        private void Debug_CheckedChanged(object sender, EventArgs e)
        {
            _doc.Configuration.Debug = _debug.Checked;
            testFunctionalityToolStripMenuItem.Visible = _debug.Checked;
        }

        private void dgActionList_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            try
            {
                DataGridView grid = sender as DataGridView;
                if (grid != null)
                {
                    if (e.Button == System.Windows.Forms.MouseButtons.Right)
                    {
                        ToolStripMenuItem menuItem;
                        _actionsMenu.Items.Clear();

                        if (e.RowIndex >= 0 && e.RowIndex < _actionsGrid.RowCount)
                        {
                            // TODO check logic of when we want to select a row
                            if (!grid.Rows[e.RowIndex].Selected)
                            {
                                grid.CancelEdit();
                                grid.ClearSelection();
                                grid.Rows[e.RowIndex].Selected = true;
                            }

                            // Load up the common properties from the selection that we may use
                            string columnName = _actionsGrid.Columns[e.ColumnIndex].HeaderText;
                            string propertyName = _actionsGrid.Columns[e.ColumnIndex].DataPropertyName;
                            string cellText = _actionsGrid[e.ColumnIndex, e.RowIndex].Value.ToString();
                            ActionItem actionItem = (ActionItem)_actionsGrid.Rows[e.RowIndex].DataBoundItem;

                            menuItem = new ToolStripMenuItem();
                            menuItem.Text = "Delete Source Files";
                            menuItem.Tag = _actionsGrid.SelectedRows;
                            menuItem.Click += DeleteSourceFileHandler;
                            _actionsMenu.Items.Add(menuItem);

                            menuItem = new ToolStripMenuItem();
                            menuItem.Text = "Ignore";
                            menuItem.Tag = _actionsGrid.SelectedRows;
                            menuItem.Click += IgnoreFileHandler;
                            _actionsMenu.Items.Add(menuItem);

                            if (actionItem != null)
                            {
                                if (File.Exists(actionItem.Source))
                                {
                                    menuItem = new ToolStripMenuItem();
                                    menuItem.Text = "Open Source";
                                    menuItem.Tag = actionItem.Source;
                                    menuItem.Click += OpenExplorerForFile;
                                    _actionsMenu.Items.Add(menuItem);
                                }

                                if (File.Exists(actionItem.Destination))
                                {
                                    menuItem = new ToolStripMenuItem();
                                    menuItem.Text = "Open Destination";
                                    menuItem.Tag = actionItem.Destination;
                                    menuItem.Click += OpenExplorerForFile;
                                    _actionsMenu.Items.Add(menuItem);
                                }
                            }

                            switch (columnName)
                            {
                                case "Source":
                                    break;

                                case "Destination":
                                    break;

                                case "Action":
                                    break;
                            }

                        }

                        menuItem = new ToolStripMenuItem();
                        menuItem.Text = "Filter by Action Type";
                        ToolStripMenuItem subMenuItem = new ToolStripMenuItem();
                        subMenuItem = new ToolStripMenuItem();
                        subMenuItem.Text = "[ALL]";
                        subMenuItem.Click += FilterListByAction;
                        menuItem.DropDownItems.Add(subMenuItem);
                        foreach (string type in Enum.GetNames(typeof(ActionItem.ActionType)))
                        {
                            subMenuItem = new ToolStripMenuItem();
                            subMenuItem.Text = type;
                            subMenuItem.Tag = type;
                            subMenuItem.Click += FilterListByAction;
                            menuItem.DropDownItems.Add(subMenuItem);
                        }
                        _actionsMenu.Items.Add(menuItem);

                        menuItem = new ToolStripMenuItem();
                        menuItem.Text = "Clear Filters";
                        menuItem.Click += (object o, EventArgs ev) => { _lastActionSerialNumber = -1; _doc.ClearFilters(); };
                        _actionsMenu.Items.Add(menuItem);

                        _actionsMenu.Show(System.Windows.Forms.Cursor.Position);
                    }
                }
            }
            catch
            {
            }
        }

        private void OpenExplorerForFile(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;

            if (sender != null)
            {
                string filename = menuItem.Tag as string;

                if (filename != null)
                {
                    if (!File.Exists(filename))
                    {
                        return;
                    }

                    // combine the arguments together
                    // it doesn't matter if there is a space after ','
                    string argument = @"/select, " + filename;

                    System.Diagnostics.Process.Start("explorer.exe", argument);
                }
            }
        }

        private void FilterListByAction(object senderMenu, EventArgs ev)
        {
            ToolStripMenuItem menuItem = senderMenu as ToolStripMenuItem;

            if (menuItem != null)
            {
                string action = menuItem.Tag as string;

                if (menuItem.Text.Equals("[ALL]"))
                {
                    _doc.ClearFilters();
                }
                else
                {
                    _doc.FilterActionsByAction(action);
                }
                // set the last serial to -1 to force a refresh of the data
                _lastActionSerialNumber = -1;
            }
        }

        private void IgnoreFileHandler(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                DataGridViewSelectedRowCollection rowCollection = (DataGridViewSelectedRowCollection)menuItem.Tag;

                foreach (DataGridViewRow row in rowCollection)
                {
                    ActionItem actionItem = row.DataBoundItem as ActionItem;
                    actionItem.Action = ActionItem.ActionType.IGNORE;
                }
            }
        }

        private void DeleteSourceFileHandler(object sender, EventArgs ev)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                DataGridViewSelectedRowCollection dgrc = (DataGridViewSelectedRowCollection)menuItem.Tag;

                ActionItems actions = PrepareDeleteFileList(dgrc);

                if (actions != null)
                {
                    _doc.DeleteFiles(actions);
                }
            }
        }

        private ActionItems PrepareDeleteFileList(DataGridViewSelectedRowCollection rowCollection)
        {
            ActionItems actions = new ActionItems();

            bool deleteNonErrorFiles = false;
            bool cancelAction = false;
            bool suppressWarning = false;

            foreach (DataGridViewRow row in rowCollection)
            {
                ActionItem actionItem = (ActionItem)row.DataBoundItem;

                if (actionItem.Action == ActionItem.ActionType.ERROR)
                {
                    actions.Add(actionItem);
                }
                else
                {
                    if (deleteNonErrorFiles)
                    {
                        actions.Add(actionItem);
                    }
                    else
                    {
                        if (!suppressWarning)
                        {
                            DialogResult result = MessageBox.Show("Delete files without error?", "Are you sure?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
                            switch (result)
                            {
                                case System.Windows.Forms.DialogResult.Yes:
                                    deleteNonErrorFiles = true;
                                    break;
                                case System.Windows.Forms.DialogResult.No:
                                    suppressWarning = true;
                                    break;
                                case System.Windows.Forms.DialogResult.Cancel:
                                    cancelAction = true;
                                    break;
                            }

                            if (deleteNonErrorFiles)
                            {
                                actions.Add(actionItem);
                            }
                        }
                    }
                }
                if (cancelAction == true)
                {
                    return null;
                }
            }

            return actions;
        }

        private void UpdateTitle(string fileName)
        {
            if (fileName == null)
            {
                this.Text = "FileRename - Default Configuration";
            }
            else
            {
                this.Text = "FileRename - " + fileName;
            }
        }

        private void dgRegExpressions_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
        {

        }

        private void dgRegExpressions_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView grid = sender as DataGridView;
            if (grid != null)
            {
                string rowName = grid.Columns[e.ColumnIndex].HeaderText;

                switch (rowName)
                {
                    case "Priority":
                        if (_doc.Configuration.AutoSortExpressions)
                        {
                            _doc.OrderRulesByPriority();
                        }
                        break;
                }
            }
        }

        private void dgRegExpressions_MouseLeave(object sender, EventArgs e)
        {
            _toolTip.View = false;
        }

        private void dgActions_MouseMove(object sender, MouseEventArgs e)
        {
            DataGridView grid = sender as DataGridView;

            if (grid != null)
            {
                if (grid.IsCurrentCellInEditMode || _actionsMenu.Visible == true)
                {
                    _toolTip.View = false;
                }
                else
                {

                    _toolTip.Position = this.PointToClient(System.Windows.Forms.Cursor.Position);
                    _toolTip.View = true;
                }
            }
        }

        private void dgRegExpressions_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridView grid = sender as DataGridView;

            if (grid != null)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    ToolStripMenuItem toolStripMenuItem;
                    cmRegularExpressions.Items.Clear();

                    if (e.RowIndex >= 0 && e.RowIndex < _expressionGrid.RowCount)
                    {
                        // TODO check logic of when we want to select a row
                        if (!grid.Rows[e.RowIndex].Selected)
                        {
                            grid.CancelEdit();
                            grid.ClearSelection();
                            grid.Rows[e.RowIndex].Selected = true;
                        }

                        // Load up the common properties from the selection that we may use
                        string columnName = _expressionGrid.Columns[e.ColumnIndex].HeaderText;
                        string propertyName = _expressionGrid.Columns[e.ColumnIndex].DataPropertyName;
                        RegReplace regularExpression = _expressionGrid.Rows[e.RowIndex].DataBoundItem as RegReplace;

                        toolStripMenuItem = new ToolStripMenuItem();
                        toolStripMenuItem.Text = "Duplicate Item";
                        toolStripMenuItem.Tag = regularExpression;
                        toolStripMenuItem.Click += DuplicateExpression;
                        cmRegularExpressions.Items.Add(toolStripMenuItem);

                        toolStripMenuItem = new ToolStripMenuItem();
                        toolStripMenuItem.Text = "Delete Item";
                        toolStripMenuItem.Tag = regularExpression;
                        toolStripMenuItem.Click += DeleteExpression;
                        cmRegularExpressions.Items.Add(toolStripMenuItem);

                        switch (columnName)
                        {
                            case "Source":
                                break;

                            case "Destination":
                                break;

                            case "Action":
                                break;
                        }

                    }

                    cmRegularExpressions.Show(System.Windows.Forms.Cursor.Position);
                }
            }
        }

        public void DuplicateExpression(object sender, EventArgs ev)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                RegReplace expression = menuItem.Tag as RegReplace;
                if (expression != null)
                {
                    _doc.Configuration.ExpressionList.Add(new RegReplace(expression.RegExp, expression.RepString, expression.Type));

                    _expressionGrid.Refresh();

                    if (_doc.Configuration.AutoSortExpressions)
                    {
                        _doc.OrderRulesByPriority();
                    }
                }
            }
        }

        public void DeleteExpression(object sender, EventArgs ev)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                RegReplace expression = menuItem.Tag as RegReplace;
                if (expression != null)
                {
                    _doc.Configuration.ExpressionList.Remove(expression);

                    _expressionGrid.Refresh();

                    if (_doc.Configuration.AutoSortExpressions)
                    {
                        _doc.OrderRulesByPriority();
                    }
                }
            }
        }

        private void cbOverwrite_CheckedChanged(object sender, EventArgs e)
        {
            _doc.Configuration.Overwrite = _overwrite.Checked;
        }

        private void StatusText(params string[] statusText)
        {
            ToolStripLabel[] statusLabels = new ToolStripLabel[] {lbStatus1, lbStatusValue1, lbStatus2, lbStatusValue2, lbStatus3, lbStatusValue3, lbStatus4, lbStatusValue4, lbStatus5, lbStatusValue5};

            int itemCount = statusText.Count() / 2;

            for (int count = 0; count < statusLabels.Count(); count++)
            {
                if ((count / 2) < itemCount)
                {
                    statusLabels[count].Visible = true;
                    statusLabels[count].Text = statusText[count];
                }
                else
                {
                    statusLabels[count].Visible = false;
                }
            }
        
        }

        private void mnuAutoSortExpressions_Click(object sender, EventArgs e)
        {
            _autoSort.Checked = !_autoSort.Checked;
            _doc.Configuration.AutoSortExpressions = _autoSort.Checked;
            if (_doc.Configuration.AutoSortExpressions)
            {
                _doc.OrderRulesByPriority();
            }
        }

        private void dgActions_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }
    }

    // TODO when refactoring to use libraries this needs to be moved out
    public static class ExtensionMethods
    {
        public static void DoubleBuffered(this DataGridView grid, bool setting)
        {
            Type type = grid.GetType();
            PropertyInfo propertyInfo = type.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
            propertyInfo.SetValue(grid, setting, null);
        }
    }

}
